<!DOCTYPE html>

<html>
<head>
  <title>renderer.coffee</title>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
  <link rel="stylesheet" media="all" href="docco.css" />
</head>
<body>
  <div id="container">
    <div id="background"></div>
    
      <ul id="jump_to">
        <li>
          <a class="large" href="javascript:void(0);">Jump To &hellip;</a>
          <a class="small" href="javascript:void(0);">+</a>
          <div id="jump_wrapper">
          <div id="jump_page">
            
              
              <a class="source" href="analyze.html">
                analyze.coffee
              </a>
            
              
              <a class="source" href="autoload.html">
                autoload.coffee
              </a>
            
              
              <a class="source" href="blender.html">
                blender.coffee
              </a>
            
              
              <a class="source" href="calculate.html">
                calculate.coffee
              </a>
            
              
              <a class="source" href="caman.html">
                caman.coffee
              </a>
            
              
              <a class="source" href="convert.html">
                convert.coffee
              </a>
            
              
              <a class="source" href="event.html">
                event.coffee
              </a>
            
              
              <a class="source" href="filter.html">
                filter.coffee
              </a>
            
              
              <a class="source" href="io.html">
                io.coffee
              </a>
            
              
              <a class="source" href="layer.html">
                layer.coffee
              </a>
            
              
              <a class="source" href="logger.html">
                logger.coffee
              </a>
            
              
              <a class="source" href="module.html">
                module.coffee
              </a>
            
              
              <a class="source" href="pixel.html">
                pixel.coffee
              </a>
            
              
              <a class="source" href="plugin.html">
                plugin.coffee
              </a>
            
              
              <a class="source" href="renderer.html">
                renderer.coffee
              </a>
            
              
              <a class="source" href="store.html">
                store.coffee
              </a>
            
              
              <a class="source" href="util.html">
                util.coffee
              </a>
            
              
              <a class="source" href="blenders.html">
                blenders.coffee
              </a>
            
              
              <a class="source" href="filters.html">
                filters.coffee
              </a>
            
              
              <a class="source" href="size.html">
                size.coffee
              </a>
            
              
              <a class="source" href="blur.html">
                blur.coffee
              </a>
            
              
              <a class="source" href="camera.html">
                camera.coffee
              </a>
            
              
              <a class="source" href="compoundBlur.html">
                compoundBlur.coffee
              </a>
            
              
              <a class="source" href="edges.html">
                edges.coffee
              </a>
            
              
              <a class="source" href="posterize.html">
                posterize.coffee
              </a>
            
              
              <a class="source" href="presets.html">
                presets.coffee
              </a>
            
              
              <a class="source" href="rotate.html">
                rotate.coffee
              </a>
            
              
              <a class="source" href="stackBlur.html">
                stackBlur.coffee
              </a>
            
              
              <a class="source" href="threshold.html">
                threshold.coffee
              </a>
            
          </div>
        </li>
      </ul>
    
    <ul class="sections">
        
          <li id="title">
              <div class="annotation">
                  <h1>renderer.coffee</h1>
              </div>
          </li>
        
        
        
        <li id="section-1">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-1">&#182;</a>
              </div>
              <p>Handles all of the various rendering methods in Caman. Most of the image modification happens 
here. A new Renderer object is created for every render operation.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre><span class="class"><span class="keyword">class</span> <span class="title">Caman</span>.<span class="title">Renderer</span></span></pre></div></div>
            
        </li>
        
        
        <li id="section-2">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-2">&#182;</a>
              </div>
              <p>The number of blocks to split the image into during the render process to simulate 
concurrency. This also helps the browser manage the (possibly) long running render jobs.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>  <span class="property">@Blocks</span> = <span class="keyword">if</span> Caman.NodeJS <span class="keyword">then</span> require(<span class="string">'os'</span>).cpus().length <span class="keyword">else</span> <span class="number">4</span>

  constructor: (<span class="property">@c</span>) -&gt;
    <span class="property">@renderQueue</span> = []
    <span class="property">@modPixelData</span> = <span class="literal">null</span>

  add: (job) -&gt;
    <span class="keyword">return</span> <span class="keyword">unless</span> job?
    <span class="property">@renderQueue</span>.push job</pre></div></div>
            
        </li>
        
        
        <li id="section-3">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-3">&#182;</a>
              </div>
              <p>Grabs the next operation from the render queue and passes it to Renderer
for execution</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>  processNext: =&gt;</pre></div></div>
            
        </li>
        
        
        <li id="section-4">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-4">&#182;</a>
              </div>
              <p>If the queue is empty, fire the finished callback</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    <span class="keyword">if</span> <span class="property">@renderQueue</span>.length <span class="keyword">is</span> <span class="number">0</span>
      Event.trigger @, <span class="string">"renderFinished"</span>
      <span class="property">@finishedFn</span>.call(<span class="property">@c</span>) <span class="keyword">if</span> <span class="property">@finishedFn</span>?

      <span class="keyword">return</span> @

    <span class="property">@currentJob</span> = <span class="property">@renderQueue</span>.shift()

    <span class="keyword">switch</span> <span class="property">@currentJob</span>.type
      <span class="keyword">when</span> Filter.Type.LayerDequeue
        layer = <span class="property">@c</span>.canvasQueue.shift()
        <span class="property">@c</span>.executeLayer layer
        <span class="property">@processNext</span>()
      <span class="keyword">when</span> Filter.Type.LayerFinished
        <span class="property">@c</span>.applyCurrentLayer()
        <span class="property">@c</span>.popContext()
        <span class="property">@processNext</span>()
      <span class="keyword">when</span> Filter.Type.LoadOverlay
        <span class="property">@loadOverlay</span> <span class="property">@currentJob</span>.layer, <span class="property">@currentJob</span>.src
      <span class="keyword">when</span> Filter.Type.Plugin
        <span class="property">@executePlugin</span>()
      <span class="keyword">else</span>
        <span class="property">@executeFilter</span>()

  execute: (callback) -&gt;
    <span class="property">@finishedFn</span> = callback
    <span class="property">@modPixelData</span> = Util.dataArray(<span class="property">@c</span>.pixelData.length)

    <span class="property">@processNext</span>()

  eachBlock: (fn) -&gt;</pre></div></div>
            
        </li>
        
        
        <li id="section-5">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-5">&#182;</a>
              </div>
              <p>Prepare all the required render data</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    <span class="property">@blocksDone</span> = <span class="number">0</span>

    n = <span class="property">@c</span>.pixelData.length
    blockPixelLength = Math.floor (n / <span class="number">4</span>) / Renderer.Blocks
    blockN = blockPixelLength * <span class="number">4</span>
    lastBlockN = blockN + ((n / <span class="number">4</span>) % Renderer.Blocks) * <span class="number">4</span>

    <span class="keyword">for</span> i <span class="keyword">in</span> [<span class="number">0.</span>..Renderer.Blocks]
      start = i * blockN
      end = start + (<span class="keyword">if</span> i <span class="keyword">is</span> Renderer.Blocks - <span class="number">1</span> <span class="keyword">then</span> lastBlockN <span class="keyword">else</span> blockN)

      <span class="keyword">if</span> Caman.NodeJS
        f = Fiber =&gt; fn.call(@, i, start, end)
        bnum = f.run()
        <span class="property">@blockFinished</span>(bnum)
      <span class="keyword">else</span>
        setTimeout <span class="keyword">do</span> (i, start, end) =&gt;
          =&gt; fn.call(@, i, start, end)
        , <span class="number">0</span></pre></div></div>
            
        </li>
        
        
        <li id="section-6">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-6">&#182;</a>
              </div>
              <p>The core of the image rendering, this function executes the provided filter.</p>
<p>NOTE: this does not write the updated pixel data to the canvas. That happens when all filters 
are finished rendering in order to be as fast as possible.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>  executeFilter: -&gt;
    Event.trigger <span class="property">@c</span>, <span class="string">"processStart"</span>, <span class="property">@currentJob</span>

    <span class="keyword">if</span> <span class="property">@currentJob</span>.type <span class="keyword">is</span> Filter.Type.Single
      <span class="property">@eachBlock</span> <span class="property">@renderBlock</span>
    <span class="keyword">else</span>
      <span class="property">@eachBlock</span> <span class="property">@renderKernel</span></pre></div></div>
            
        </li>
        
        
        <li id="section-7">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-7">&#182;</a>
              </div>
              <p>Executes a standalone plugin</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>  executePlugin: -&gt;
    Log.debug <span class="string">"Executing plugin <span class="subst">#{@currentJob.plugin}</span>"</span>
    Plugin.execute <span class="property">@c</span>, <span class="property">@currentJob</span>.plugin, <span class="property">@currentJob</span>.args
    Log.debug <span class="string">"Plugin <span class="subst">#{@currentJob.plugin}</span> finished!"</span>

    <span class="property">@processNext</span>()</pre></div></div>
            
        </li>
        
        
        <li id="section-8">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-8">&#182;</a>
              </div>
              <p>Renders a single block of the canvas with the current filter function</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>  renderBlock: (bnum, start, end) -&gt;
    Log.debug <span class="string">"Block #<span class="subst">#{bnum}</span> - Filter: <span class="subst">#{@currentJob.name}</span>, Start: <span class="subst">#{start}</span>, End: <span class="subst">#{end}</span>"</span>
    Event.trigger <span class="property">@c</span>, <span class="string">"blockStarted"</span>,
      blockNum: bnum
      totalBlocks: Renderer.Blocks
      startPixel: start
      endPixel: end

    pixel = <span class="keyword">new</span> Pixel()
    pixel.setContext <span class="property">@c</span>

    <span class="keyword">for</span> i <span class="keyword">in</span> [start...end] <span class="keyword">by</span> <span class="number">4</span>
      pixel.loc = i

      pixel.r = <span class="property">@c</span>.pixelData[i]
      pixel.g = <span class="property">@c</span>.pixelData[i+<span class="number">1</span>]
      pixel.b = <span class="property">@c</span>.pixelData[i+<span class="number">2</span>]
      pixel.a = <span class="property">@c</span>.pixelData[i+<span class="number">3</span>]

      <span class="property">@currentJob</span>.processFn pixel

      <span class="property">@c</span>.pixelData[i]   = Util.clampRGB pixel.r
      <span class="property">@c</span>.pixelData[i+<span class="number">1</span>] = Util.clampRGB pixel.g
      <span class="property">@c</span>.pixelData[i+<span class="number">2</span>] = Util.clampRGB pixel.b
      <span class="property">@c</span>.pixelData[i+<span class="number">3</span>] = Util.clampRGB pixel.a

    <span class="keyword">if</span> Caman.NodeJS
      Fiber.yield(bnum)
    <span class="keyword">else</span>
      <span class="property">@blockFinished</span> bnum</pre></div></div>
            
        </li>
        
        
        <li id="section-9">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-9">&#182;</a>
              </div>
              <p>Applies an image kernel to the canvas</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>  renderKernel: (bnum, start, end) -&gt;
    name = <span class="property">@currentJob</span>.name
    bias = <span class="property">@currentJob</span>.bias
    divisor = <span class="property">@currentJob</span>.divisor
    n = <span class="property">@c</span>.pixelData.length

    adjust = <span class="property">@currentJob</span>.adjust
    adjustSize = Math.sqrt adjust.length

    kernel = []

    Log.debug <span class="string">"Rendering kernel - Filter: <span class="subst">#{@currentJob.name}</span>"</span>

    start = Math.max start, <span class="property">@c</span>.dimensions.width * <span class="number">4</span> * ((adjustSize - <span class="number">1</span>) / <span class="number">2</span>)
    end = Math.min end, n - (<span class="property">@c</span>.dimensions.width * <span class="number">4</span> * ((adjustSize - <span class="number">1</span>) / <span class="number">2</span>))

    builder = (adjustSize - <span class="number">1</span>) / <span class="number">2</span>

    pixel = <span class="keyword">new</span> Pixel()
    pixel.setContext(<span class="property">@c</span>)

    <span class="keyword">for</span> i <span class="keyword">in</span> [start...end] <span class="keyword">by</span> <span class="number">4</span>
      pixel.loc = i
      builderIndex = <span class="number">0</span>

      <span class="keyword">for</span> j <span class="keyword">in</span> [-builder..builder]
        <span class="keyword">for</span> k <span class="keyword">in</span> [builder..-builder]
          p = pixel.getPixelRelative j, k
          kernel[builderIndex * <span class="number">3</span>]     = p.r
          kernel[builderIndex * <span class="number">3</span> + <span class="number">1</span>] = p.g
          kernel[builderIndex * <span class="number">3</span> + <span class="number">2</span>] = p.b

          builderIndex++

      res = <span class="property">@processKernel</span> adjust, kernel, divisor, bias

      <span class="property">@modPixelData</span>[i]    = Util.clampRGB(res.r)
      <span class="property">@modPixelData</span>[i+<span class="number">1</span>]  = Util.clampRGB(res.g)
      <span class="property">@modPixelData</span>[i+<span class="number">2</span>]  = Util.clampRGB(res.b)
      <span class="property">@modPixelData</span>[i+<span class="number">3</span>]  = <span class="property">@c</span>.pixelData[i+<span class="number">3</span>]

    <span class="keyword">if</span> Caman.NodeJS
      Fiber.yield(bnum)
    <span class="keyword">else</span>
      <span class="property">@blockFinished</span> bnum</pre></div></div>
            
        </li>
        
        
        <li id="section-10">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-10">&#182;</a>
              </div>
              <p>Called when a single block is finished rendering. Once all blocks are done, we signal that this
filter is finished rendering and continue to the next step.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>  blockFinished: (bnum) -&gt;
    Log.debug <span class="string">"Block #<span class="subst">#{bnum}</span> finished! Filter: <span class="subst">#{@currentJob.name}</span>"</span> <span class="keyword">if</span> bnum &gt;= <span class="number">0</span>
    <span class="property">@blocksDone</span>++

    Event.trigger <span class="property">@c</span>, <span class="string">"blockFinished"</span>,
      blockNum: bnum
      blocksFinished: <span class="property">@blocksDone</span>
      totalBlocks: Renderer.Blocks

    <span class="keyword">if</span> <span class="property">@blocksDone</span> <span class="keyword">is</span> Renderer.Blocks
      <span class="keyword">if</span> <span class="property">@currentJob</span>.type <span class="keyword">is</span> Filter.Type.Kernel
        <span class="keyword">for</span> i <span class="keyword">in</span> [<span class="number">0.</span>..<span class="property">@c</span>.pixelData.length]
          <span class="property">@c</span>.pixelData[i] = <span class="property">@modPixelData</span>[i]

      Log.debug <span class="string">"Filter <span class="subst">#{@currentJob.name}</span> finished!"</span> <span class="keyword">if</span> bnum &gt;=<span class="number">0</span>
      Event.trigger <span class="property">@c</span>, <span class="string">"processComplete"</span>, <span class="property">@currentJob</span>

      <span class="property">@processNext</span>()</pre></div></div>
            
        </li>
        
        
        <li id="section-11">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-11">&#182;</a>
              </div>
              <p>The &quot;filter function&quot; for kernel adjustments.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>  processKernel: (adjust, kernel, divisor, bias) -&gt;
    val = r: <span class="number">0</span>, g: <span class="number">0</span>, b: <span class="number">0</span>

    <span class="keyword">for</span> i <span class="keyword">in</span> [<span class="number">0.</span>..adjust.length]
      val.r += adjust[i] * kernel[i * <span class="number">3</span>]
      val.g += adjust[i] * kernel[i * <span class="number">3</span> + <span class="number">1</span>]
      val.b += adjust[i] * kernel[i * <span class="number">3</span> + <span class="number">2</span>]

    val.r = (val.r / divisor) + bias
    val.g = (val.g / divisor) + bias
    val.b = (val.b / divisor) + bias
    val</pre></div></div>
            
        </li>
        
        
        <li id="section-12">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-12">&#182;</a>
              </div>
              <p>Loads an image onto the current canvas</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>  loadOverlay: (layer, src) -&gt;
    img = document.createElement <span class="string">'img'</span>
    img.<span class="function"><span class="title">onload</span></span> = =&gt;
      layer.context.drawImage img, <span class="number">0</span>, <span class="number">0</span>, <span class="property">@c</span>.dimensions.width, <span class="property">@c</span>.dimensions.height
      layer.imageData = layer.context.getImageData <span class="number">0</span>, <span class="number">0</span>, <span class="property">@c</span>.dimensions.width, <span class="property">@c</span>.dimensions.height
      layer.pixelData = layer.imageData.data

      <span class="property">@c</span>.pixelData = layer.pixelData

      <span class="property">@processNext</span>()

    proxyUrl = IO.remoteCheck src
    img.src = <span class="keyword">if</span> proxyUrl? <span class="keyword">then</span> proxyUrl <span class="keyword">else</span> src

Renderer = Caman.Renderer</pre></div></div>
            
        </li>
        
    </ul>
  </div>
</body>
</html>
